package com.lemo.smart.helper;

import com.lemo.smart.annotation.Aspect;
import com.lemo.smart.proxy.AspectProxy;
import com.lemo.smart.proxy.Proxy;
import com.lemo.smart.proxy.ProxyManager;

import org.apache.commons.collections.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 方法拦截助手
 * Created by 罗选通 on 2017/12/25.
 */
public final class AopHelper {
  private final static Logger logger = LoggerFactory.getLogger(AopHelper.class);

  static {
    try {
      //切面和目标类的映射
      Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
      //为目标类添加代理类
      Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
      for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
        Class<?> key = targetEntry.getKey();
        List<Proxy> value = targetEntry.getValue();
        Object proxy = ProxyManager.createProxy(key, value);
        BeanHelper.setBean(key, proxy);
      }
    } catch (Exception e) {
      logger.error("aop failure", e);
    }
  }

  private static Set<Class<?>> createTargetClassSet(Aspect aspect) {
    Set<Class<?>> targetClassSet = new HashSet<>();
    Class<? extends Annotation> value = aspect.value();
    if (value != null && !value.equals(Aspect.class)) {
      targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(value));
    }
    return targetClassSet;
  }

  private static Map<Class<?>, Set<Class<?>>> createProxyMap() {
    Map<Class<?>, Set<Class<?>>> proxyMap = new HashedMap();
    Set<Class<?>> classSetBySuper = ClassHelper.getClassSetBySuper(AspectProxy.class);
    for (Class<?> proxyClass : classSetBySuper) {
      if (proxyClass.isAnnotationPresent(Aspect.class)) {
        Aspect aspect = proxyClass.getAnnotation(Aspect.class);
        Set<Class<?>> targetClassSet = createTargetClassSet(aspect);
        proxyMap.put(proxyClass, targetClassSet);
      }
    }
    return proxyMap;
  }

  private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) throws IllegalAccessException, InstantiationException {
    Map<Class<?>, List<Proxy>> targetMap = new HashedMap();
    for (Map.Entry<Class<?>, Set<Class<?>>> proxyEntry : proxyMap.entrySet()) {
      Class<?> key = proxyEntry.getKey();
      Set<Class<?>> value = proxyEntry.getValue();
      for (Class<?> cls : value) {
        Proxy proxy = (Proxy) key.newInstance();
        if (targetMap.containsKey(cls)) {
          targetMap.get(cls).add(proxy);
        } else {
          List<Proxy> proxyList = new ArrayList();
          proxyList.add(proxy);
          targetMap.put(cls, proxyList);
        }
      }
    }
    return targetMap;
  }

  private static void addAspectProxy(Map<Class<?>, Set<Class<?>>> proxyMap) throws Exception {
    // 获取切面类（所有继承于 BaseAspect 的类）
    Set<Class<?>> aspectProxyClassList = ClassHelper.getClassSetBySuper(AspectProxy.class);
    // 添加插件包下所有的切面类
//        aspectProxyClassList.addAll(classScanner.getClassListBySuper(FrameworkConstant.PLUGIN_PACKAGE, AspectProxy.class));
    // 排序切面类
//        sortAspectProxyClassList(aspectProxyClassList);
    // 遍历切面类
    for (Class<?> aspectProxyClass : aspectProxyClassList) {
      // 判断 Aspect 注解是否存在
      if (aspectProxyClass.isAnnotationPresent(Aspect.class)) {
        // 获取 Aspect 注解
        Aspect aspect = aspectProxyClass.getAnnotation(Aspect.class);
        // 创建目标类列表
        Set<Class<?>> targetClassList = createTargetClassSet(aspect);
        // 初始化 Proxy Map
        proxyMap.put(aspectProxyClass, targetClassList);
      }
    }
  }

//  private static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> proxyMap) {
//    // 使用 TransactionProxy 代理所有 Service 类
//    Set<Class<?>> serviceClassList = ClassHelper.getClassSetByAnnotation(Service.class);
//    proxyMap.put(TransactionProxy.class, serviceClassList);
//  }

}
